package com.mine.vioceplaylib.sound;

import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.SoundPool;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import com.mine.vioceplaylib.R;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 播放语音
 */
public class SoundManager {
    private int counts = 0;
    private SoundPool soundPool;
    private int statusMine = SoundStatus.SOUND_START;
    private static final int MAX_STREAM = 15;
    private LinkedList<List<Integer>> mLinkedListForPdnum = new LinkedList();
    private LinkedList<List<Integer>> mLinkedListForWindownum = new LinkedList();
    private MediaPlayer mediaPlayer;

    private SoundManager() {
        //sdk版本21是SoundPool 的一个分水岭
        if (Build.VERSION.SDK_INT >= 21) {
            SoundPool.Builder builder = new SoundPool.Builder();
            //传入最多播放音频数量,
            builder.setMaxStreams(MAX_STREAM);
            //AudioAttributes是一个封装音频各种属性的方法
            AudioAttributes.Builder attrBuilder = new AudioAttributes.Builder();
            //设置音频流的合适的属性
            attrBuilder.setLegacyStreamType(AudioManager.STREAM_DTMF);
            //加载一个AudioAttributes
            builder.setAudioAttributes(attrBuilder.build());

            soundPool = builder.build();
        } else {
            /**
             * 第一个参数：int maxStreams：SoundPool对象的最大并发流数
             * 第二个参数：int streamType：AudioManager中描述的音频流类型
             *第三个参数：int srcQuality：采样率转换器的质量。 目前没有效果。 使用0作为默认值。
             */
            soundPool = new SoundPool(MAX_STREAM, AudioManager.STREAM_MUSIC, 0);
        }
    }

    private static class Holder {
        private static SoundManager INSTANCE = new SoundManager();
    }

    public static SoundManager getInstance() {
        return Holder.INSTANCE;
    }



    public void loadSoundWithCache(Context context, String pdNum, String windowNum) {
        if (statusMine == SoundStatus.SOUND_START) {
            loadSound(context, str2Array(pdNum), str2Array(windowNum));
        } else if (statusMine == SoundStatus.SOUND_ING) {
            addCache(pdNum, windowNum);
        }
    }

    private List<Integer> str2Array(String str) {
        if (TextUtils.isEmpty(str)) {
            return null;
        }

        char[] charsMine = str.toCharArray();
        List<Integer> integers = new ArrayList<>();

        for (char param : charsMine) {
            switch (String.valueOf(param)) {
                case "0":
                    integers.add(R.raw.t_0);
                    break;
                case "1":
                    integers.add(R.raw.t_1);
                    break;
                case "2":
                    integers.add(R.raw.t_2);
                    break;
                case "3":
                    integers.add(R.raw.t_3);
                    break;
                case "4":
                    integers.add(R.raw.t_4);
                    break;
                case "5":
                    integers.add(R.raw.t_5);
                    break;
                case "6":
                    integers.add(R.raw.t_6);
                    break;
                case "7":
                    integers.add(R.raw.t_7);
                    break;
                case "8":
                    integers.add(R.raw.t_8);
                    break;
                case "9":
                    integers.add(R.raw.t_9);
                    break;
                case "A":
                case "a":
                    integers.add(R.raw.t_a);
                    break;
                case "B":
                case "b":
                    integers.add(R.raw.t_b);
                    break;
                case "C":
                case "c":
                    integers.add(R.raw.t_c);
                    break;
                case "D":
                case "d":
                    integers.add(R.raw.t_d);
                    break;
                case "E":
                case "e":
                    integers.add(R.raw.t_e);
                    break;
                case "F":
                case "f":
                    integers.add(R.raw.t_f);
                    break;
                case "G":
                case "g":
                    integers.add(R.raw.t_g);
                    break;
                case "H":
                case "h":
                    integers.add(R.raw.t_h);
                    break;
                case "I":
                case "i":
                    integers.add(R.raw.t_i);
                    break;
                case "J":
                case "j":
                    integers.add(R.raw.t_j);
                case "K":
                case "k":
                    integers.add(R.raw.t_k);
                    break;
                case "L":
                case "l":
                    integers.add(R.raw.t_l);
                    break;
                case "M":
                case "m":
                    integers.add(R.raw.t_m);
                    break;
                case "N":
                case "n":
                    integers.add(R.raw.t_n);
                    break;
                case "O":
                case "o":
                    integers.add(R.raw.t_o);
                    break;
                case "Q":
                case "q":
                    integers.add(R.raw.t_q);
                    break;
                case "R":
                case "r":
                    integers.add(R.raw.t_r);
                    break;
                case "S":
                case "s":
                    integers.add(R.raw.t_s);
                    break;
                case "T":
                case "t":
                    integers.add(R.raw.t_t);
                    break;
                case "U":
                case "u":
                    integers.add(R.raw.t_u);
                    break;
                case "V":
                case "v":
                    integers.add(R.raw.t_v);
                    break;
                case "W":
                case "w":
                    integers.add(R.raw.t_w);
                    break;
                case "X":
                case "x":
                    integers.add(R.raw.t_x);
                    break;
                case "Y":
                case "y":
                    integers.add(R.raw.t_y);
                    break;
                case "Z":
                case "z":
                    integers.add(R.raw.t_z);
                    break;
                default:
                    break;
            }
        }

        return integers;
    }

    private void addCache(String pdNum, String windowNum) {
        if (!TextUtils.isEmpty(pdNum) && !TextUtils.isEmpty(windowNum)) {
            mLinkedListForPdnum.add(str2Array(pdNum));
            mLinkedListForWindownum.add(str2Array(windowNum));
        }
    }


    /**
     * @param context     上下文
     * @param prefixDatas 排队号码合集
     * @param subfixDatas 窗口号码集合
     */
    private void loadSound(Context context, List<Integer> prefixDatas, List<Integer> subfixDatas) {
        statusMine = SoundStatus.SOUND_ING;
        //声音ID 加载音频资源,这里用的是第二种，第三个参数为priority，声音的优先级*API中指出，priority参数目前没有效果，建议设置为1。
        List<Integer> datas = getDatas(prefixDatas, subfixDatas);

        final int voiceId = soundPool.load(context, datas.get(counts), 1);
        final int voiceDuration = getMp3Duration(context, datas.get(counts));
        //第一个参数soundID
        //第二个参数leftVolume为左侧音量值（范围= 0.0到1.0）
        //第三个参数rightVolume为右的音量值（范围= 0.0到1.0）
        //第四个参数priority 为流的优先级，值越大优先级高，影响当同时播放数量超出了最大支持数时SoundPool对该流的处理
        //第五个参数loop 为音频重复播放次数，0为值播放一次，-1为无限循环，其他值为播放loop+1次
        //第六个参数 rate为播放的速率，范围0.5-2.0(0.5为一半速率，1.0为正常速率，2.0为两倍速率)
        //异步需要等待加载完成，音频才能播放成功
        final int soundSize = prefixDatas.size();
        soundPool.setOnLoadCompleteListener((soundPool1, sampleId, status) -> {
            if (status == 0) {
                soundPool1.play(voiceId, 1, 1, 0, 0, 1);
                //non-zero streamID if successful,没有释放资源导致内存泄露
//                soundPool1.release();
//                soundPool1.unload(voiceId);
                try {
                    if (soundSize == 4) {
                        if (counts == 0) {
//                            Log.d("SoundSize0","voiceDuration:"+voiceDuration);
                            Thread.sleep(Math.abs(voiceDuration - 540));
                        } else if (counts == 4) {
//                            Log.d("SoundSize4","voiceDuration:"+voiceDuration);

                            Thread.sleep(Math.abs(voiceDuration - 510));
                        } else if (counts == 5) {
//                            Log.d("SoundSize5","voiceDuration:"+voiceDuration);

                            Thread.sleep(Math.abs(voiceDuration - 500));
                        } else if (counts == 7) {
//                            Log.d("SoundSize7","voiceDuration:"+voiceDuration);

                            Thread.sleep(Math.abs(voiceDuration - 510));
                        } else {

                            Thread.sleep(Math.abs(voiceDuration - 880));
                        }
                    } else {
//                        if (counts == 0) {
//                            Log.d("SoundSize0else","voiceDuration:"+voiceDuration);
//
//                            Thread.sleep(Math.abs(voiceDuration - 300));
//                        } else if (counts == 5) {
//                            Log.d("SoundSize5else","voiceDuration:"+voiceDuration);
//
//                            Thread.sleep(Math.abs(voiceDuration - 380));
//                        } else if (counts == 6) {
//                            Log.d("SoundSize6else","voiceDuration:"+voiceDuration);
//
//                            Thread.sleep(Math.abs(voiceDuration - 500));
//                        } else if (counts == 8) {
//                            Log.d("SoundSize8else","voiceDuration:"+voiceDuration);
//
//                            Thread.sleep(Math.abs(voiceDuration - 480));
//                        } else {
//                            Log.d("SoundSizeelse","voiceDuration:"+voiceDuration);
//                            Thread.sleep(Math.abs(voiceDuration - 850));
//                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }


                counts++;
                if (counts < datas.size()) {
                    loadSound(context, prefixDatas, subfixDatas);
                } else {

                    finishOrSpeakWithCache(context);
                }
            }
        });

    }

    /**
     * 如果缓存没有数据，设置状态未初始化状态
     * 如果缓存有数据播放缓存中的数据，同时将队列首位移除队列
     *
     * @param context 上下文
     */
    private void finishOrSpeakWithCache(Context context) {
        counts = 0;
        statusMine = SoundStatus.SOUND_END;

        if (mLinkedListForPdnum == null || mLinkedListForPdnum.isEmpty()) {
            mLinkedListForPdnum = new LinkedList<>();
            statusMine = SoundStatus.SOUND_START;
            return;
        }

        if (mLinkedListForWindownum == null || mLinkedListForWindownum.isEmpty()) {
            mLinkedListForWindownum = new LinkedList<>();
            statusMine = SoundStatus.SOUND_START;
            return;
        }

        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        loadSound(context, mLinkedListForPdnum.getFirst(), mLinkedListForWindownum.getFirst());
        mLinkedListForWindownum.removeFirst();
        mLinkedListForPdnum.removeFirst();
    }


    private List<Integer> getDatas(List<Integer> prefixDatas, List<Integer> subfixDatas) {
        List<Integer> datas = new ArrayList<>();
        datas.add(R.raw.pl);
        datas.addAll(prefixDatas);
        datas.add(R.raw.num);
        datas.add(R.raw.to);
        datas.addAll(subfixDatas);
        datas.add(R.raw.last);
        return datas;
    }

    /**
     * 获取音频文件的时长
     */
    private int getMp3Duration(Context context, int rawId) {
        try {
            Uri uri = Uri.parse("android.resource://" + context.getPackageName() + "/" + rawId);
            if (mediaPlayer==null){
                mediaPlayer = new MediaPlayer();
            }
            mediaPlayer.reset();
            mediaPlayer.setDataSource(context, uri);
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.prepare();
            return mediaPlayer.getDuration();
        } catch (IOException e) {
            e.printStackTrace();
            if (mediaPlayer != null) {
                mediaPlayer.release();
                mediaPlayer = null;
            }
        }
        return 0;
    }

}
